home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Speccy ClassiX 1998
/
Speccy ClassiX 98.iso
/
amiga_system
/
the_aminet
/
dev
/
gcc
/
ixemulsrc.lha
/
ixemul-41.4
/
library
/
trap.s
< prev
next >
Wrap
Text File
|
1995-10-03
|
14KB
|
503 lines
/*
* This file is part of ixemul.library for the Amiga.
* Copyright (C) 1991, 1992 Markus M. Wild
* Portions Copyright (C) 1994 Rafael W. Luebbert
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the Free
* Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Id: trap.s,v 1.1 1994/06/19 15:17:35 rluebbert Exp $
*
* $Log: trap.s,v $
# Revision 1.1 1994/06/19 15:17:35 rluebbert
# Initial revision
#
*/
.globl _trap_00
.globl _restore_00
.globl _sup00_do_sigreturn
.globl _sup00_do_sigreturn_ssp
.globl _trap_20
.globl _restore_20
.globl _sup20_do_sigreturn
.globl _sup20_do_sigreturn_ssp
.globl _supervisor
.globl _do_sigreturn
.globl _launch_glue
.globl _addupc
.globl _resetfpu
#undef DEBUG
|
| ATTENTION:
|
| do_sigreturn() uses absolute offsets into struct user.
| if you change struct user, be sure to check whether the current
| offsets of p_sigmask and u_onstack are still valid !!!!
|
| This is the trap processing function for the mc68000.
| Things are quite easy here, just save the general purpose registers
| and the pc/sr combo, call trap(), then restore the previous
| context and return
_trap_00:
movel a5,sp@- | need a scratch register
movel usp,a5 | get usp
moveml d0-d7/a0-a6,a5@-| store registers on usp
movel sp@+,a5@(0x34) | insert the saved a5 into the saveset
movel sp@+,d2 | remember trapnumber
movew sp@+,a5@- | copy SR
movel sp@+,a0 | remember and
movel a0,a5@- | copy offending PC
|
| pass return address and ssp-value on userstack
| This happens for the same reason as we have a glue_launch entry.
| trap cleans up these 8 bytes on the user stack itself
movel sp,a5@-
movel #_restore_00,a5@-
movel a5,usp | and remember current value of usp (a5)
| fine, now process this trap. This might (doesn't have to) push
| additional frames. If not, we just return where the exception
| took place (and probably will again...)
movel a0,sp@- | pass offending address (don't know more about it)
addl d2,d2 | convert the passed trap number into a fake
addl d2,d2 | 68020 frame format word
movel d2,sp@- | and pass it as argument
jsr _trap | to the higher level C trap
lea sp@(8),sp | processor
_restore_00:
movel usp,a5 | get usp
lea a5@(0x42),a1 | skip over the now no longer needed frame
movel a1,usp | -> 15 registers, one PC and one SR
| set up the original supervisor stack frame
movel a5@+,sp@- | PC
movew a5@+,sp@- | SR
moveml a5@,d0-d7/a0-a6 | and the other cpu registers
rte
| This is the trap processor for the mc68020 and above, paired with
| an fpu (don't *need* an fpu though).
| What is done: start is same as with 68000, but then the complete
| additional exception frame is saved on the usp, together with the
| fpu state. Then trap() is called, and then the previous context
| is restored (involves copying back the frame from the usp over to the ssp)
_trap_20:
movel a5,sp@ | nuke the trap number, we use the frame format word
movel usp,a5 | get usp
moveml d0-d7/a0-a6,a5@-| store registers on usp
movel sp@+,a5@(0x34) | insert the saved a5 into the saveset
movew sp@+,a5@- | copy SR
movel sp@+,d2 | remember and
movel d2,a5@- | copy (offending?) PC
| find out more about the frame (according to the MC68030 user manual)
clrl d1
movew sp@+,d1 | remember frame format word
movew d1,d0
andw #0xf000,d0
beq Lfmt_S0 | S0
cmpw #0x1000,d0
beq Lfmt_S1 | S1 this (interrupt) frame shouldn't be here...
cmpw #0x2000,d0
beq Lfmt_S2 | CHK{2},cpTRAPcc,TRAPV,Trace,Div0,MMUcfg,cp post instr
cmpw #0x9000,d0
beq Lfmt_S9 | cp mid instr,main det prot viol,int during cp instr
cmpw #0xa000,d0
beq Lfmt_SA_SB | address or bus error, short and long frame
cmpw #0xb000,d0
bne Lfmt_S0 | ??? frame, this will probably not fully cleanup sp..
Lfmt_SA_SB:
| this part (upto Lbe10) inspired by locore.s in sys/hp300/ of BSD4.3-reno
movew sp@(2),d0 | grab SSW for fault processing
btst #12,d0 | RB set?
beq LbeX0 | no, test RC
bset #14,d0 | yes, must set FB
movew d0,sp@(2) | for hardware too
LbeX0:
btst #13,d0 | RC set?
beq LbeX1 | no, skip
bset #15,d0 | yes, must set FC
movew d0,sp@(2) | for hardware too
LbeX1:
btst #8,d0 | data fault?
beq Lbe0 | no, check for hard cases
movel sp@(8),d2 | fault address is as given in frame
bra Lbe10 | thats it
Lbe0:
btst #12,d1 | long (type B) stack frame?
bne Lbe4 | yes, go handle
btst #14,d0 | no, can use saved PC. FB set?
beq Lbe3 | no, try FC
addql #4,d2 | yes, adjust address
bra Lbe10 | done
Lbe3:
btst #15,d0 | FC set?
beq Lbe10 | no, done
addql #2,d2 | yes, adjust address
bra Lbe10 | done
Lbe4:
movel sp@(28),d2 | long format, use stage B address
btst #15,d0 | FC set?
beq Lbe10 | no, all done
subql #2,d2 | yes, adjust address
Lbe10:
| now move the frame over to the usp (6/21 longwords remain)
moveml sp@+,d3-d7/a0 | may trash as many registers as I like, I saved
moveml d3-d7/a0,a5@- | them already ;-) First copy 6 longs
btst #12,d1 | long (type B) stack frame?
beq Lfmt_S0 | nope, done
moveml sp@+,d3-d7/a0-a2 | first copy 8 longs
moveml d3-d7/a0-a2,a5@-
moveml sp@+,d3-d7/a0-a1 | plus 7 gives 15, plus already stored 6 is 21
moveml d3-d7/a0-a1,a5@-
bra Lfmt_S0 | finito
Lfmt_S9:
movel sp@+,a5@- | S9 is an S2 plus 4 internal (word length) registers
movel sp@+,a5@- | so store those registers, and fall into S2
Lfmt_S2:
movel sp@+,d2 | S2 contains the offending instruction address
| and the frame format word
movel d2,a5@- | we have the offending instruction address here
| fall into
Lfmt_S0:
Lfmt_S1:
movew d1,a5@- | and as the last thing store the frame format word
|
| now lets look at the fpu, if there is an fpu in the system
|
btst #4,(4)@(0x129) | is AFB_68881 set in SysBase->AttnFlags ??
beq Lno_fpu
fsave a5@- | dump the fpu state onto the usp
moveb a5@,d0 | and get the fpu state identifier
beq Lno_fpu | null frame?
clrl d0
moveb a5@(1),d0 | load state frame size
bset #3,a5@(d0) | set bit 27 of BIU
fmovemx fp0-fp7,a5@- | push the fpu data registers and
fmoveml fpcr/fpsr/fpi,a5@- | fpu control registers
movew #-1,a5@- | mark that there is fpu stuff on the stack
Lno_fpu:
|
| pass return address and ssp-value on userstack
| This happens for the same reason as we have a glue_launch entry.
| trap cleans up these 8 bytes on the user stack itself
movel sp,a5@-
movel #_restore_20,a5@-
movel a5,usp | set the new value of the usp
| that's it, phew.. now process this frame, and perhaps throw some
| frames on it as well to deal with the signal
movel d2,sp@- | pass offending PC
movel d1,sp@- | pass frame format word
jsr _trap | do distribution in C ;-)
lea sp@(8),sp
_restore_20:
|
| restore the saved stack frame from the usp, and copy the necessary
| parts over to the ssp
|
movel usp,a5
| first deal with fpu stuff, if there's an fpu
btst #4,(4)@(0x129) | is AFB_68881 set in SysBase->AttnFlags ??
beq Lno_fpu2
tstb a5@
beq Lrst_fpu_frame | there's only the null frame, go and restore it
lea a5@(2),a5 | skip fpu indicator
fmoveml a5@+,fpcr/fpsr/fpi | restore fpu control and
fmovemx a5@+,fp0-fp7 | fpu data registers
Lrst_fpu_frame:
frestore a5@+ | and restore the internal fpu state
Lno_fpu2:
movew a5@+,d1 | get frame format word
movew d1,d0
andw #0xf000,d0
beq Lrfmt_S0 | S0
cmpw #0x1000,d0
beq Lrfmt_S1 | S1
cmpw #0x2000,d0
beq Lrfmt_S2 | S2
cmpw #0x9000,d0
beq Lrfmt_S9 | S9
cmpw #0xa000,d0
beq Lrfmt_SA | SA
cmpw #0xb000,d0
bne Lrfmt_S0 | ??? frame
Lrfmt_SB:
moveml a5@+,d3-d7/a0-a2
moveml d3-d7/a0-a2,sp@-
moveml a5@+,d3-d7/a0-a1
moveml d3-d7/a0-a1,sp@- | copy 15 longs
Lrfmt_SA:
movel a5@+,sp@- | copy 3 longs
movel a5@+,sp@-
movel a5@+,sp@-
Lrfmt_S9:
movel a5@+,sp@- | copy 2 longs
movel a5@+,sp@-
Lrfmt_S2:
movel a5@+,sp@- | copy 1 long
Lrfmt_S1:
Lrfmt_S0:
movew d1,sp@- | insert frame format word
movel a5@+,sp@- | copy PC
movew a5@+,sp@- | and SR
lea a5@(0x3c),a1 | skip the rest of the frame
movel a1,usp | 0x3c -> 15 registers
moveml a5@,d0-d7/a0-a6 | restore the cpu registers
rte | that's it (finally) ..
|
| jump to the given argument in supervisor mode
| does NOT return
|
_supervisor:
movel sp@(4),a5 | where to go in supervisor
movel sp@(8),sp@- | with this usp
movel a6,sp@-
movel 4:w,a6
jmp a6@(-0x1e) | do it (Supervisor() system call)
|
| restore signal context
| argument comes in usp
|
| mc68020 entry
_sup20_do_sigreturn_ssp: | entry via jsr from supervisor mode
movel sp@(4),sp | set ssp
_sup20_do_sigreturn:
lea sp@(-8),sp | make room for an exception frame
movew #0x20,sp@(6) | fake format word
bra fromsup_sigreturn
| mc68000 entry
_sup00_do_sigreturn_ssp:
movel sp@(4),sp | set ssp
_sup00_do_sigreturn:
lea sp@(-6),sp | make room for an exception frame
fromsup_sigreturn:
moveml d0/d1/a0/a1,sp@-
movel usp,a0 | get signal context
bra resume_sigreturn
| fall into _do_sigreturn
| Supervisor() entry (already comes on exception frame)
_do_sigreturn:
| make the sigreturn() function preserve all registers
moveml d0/d1/a0/a1,sp@-
movel usp,a0 | get signal context
movel a0@+,a6 | restore the trashed a6 register
movel a0@,a0
resume_sigreturn:
movel 4:w,a1 | SysBase
movel a1,d1 | remember for later setting of sc_ap
movel a1@(0x114),a1 | ThisTask
movel a1@(0x2e),a1 | TrapData -> (struct user *)
| ok, now a0:sc, a1:u
| get those offsets in struct user with `print_user.c' !
movel a0@+,a1@(0x11c) | u.u_onstack = sc->sc_onstack
movel a0@+,a1@(0x134) | u.p_sigmask = sc->sc_mask
movel a0@+,a1 | usp = sc->sc_sp
movel a1,usp
movel a0@+,a5 | fp = sc->sc_fp
movel d1,a1 | get back SysBase
movel a1@(0x114),a1 | ThisTask
movel a0@,a1@(0x0e) | store Flags,State,IDNestCnt,TDNestCnt
movel d1,a1
lea a0@(2),a0 | skip unused part of sc_ap
movew a0@+,d1 | get IDNestCnt and TDNestCnt
movew d1,a1@(0x126) | store them in SysBase
tstb a1@(0x126)
bmi Lenable
Ldisabled:
movew #0x4000,0xdff09a | disable interrupts
bra Lint_twiddle
Lenable:
movew #0xc000,0xdff09a | enable interrupts
Lint_twiddle:
| set pc and sr in current exception frame
movel a0@+,sp@(2+4*4) | set PC
movew a0@(2),sp@(4*4) | and SR
moveml sp@+,d0/d1/a0/a1
rte
|
| launch_glue is used to invoke the sig_launch handler. We have to care to
| clean the supervisor stack, if we should call a signal handler from
| the launch handler.
| The bad thing is, that doing this right needs information on how
| the tc_Launch entry is called from the OS. Thus I pass two parameters
| on the user stack, the value of the `virgin' ssp and the value of
| a4, which happens to contain the address of the context restore
| function.
| It is assumed, that tc_Launch is called via
| ... jsr sub
| ...
| sub:jsr tc_Launch
| Thus we have to backup the sp by two jsr's, which is 8.
_launch_glue:
movel 4:w,a0
movel a0@(0x114),a0 | tid = SysBase->ThisTask
movel a0@(0x36),a0 | usp isn't setup correctly, do it now from tc_SPReg
movel sp,a0@-
addl #8,a0@
movel a4,a0@-
movel a0,usp
jsr _sig_launch | sig_launch `(void *pc_ret, *ssp_ret)' (`' on usp)
| sig_launch() already corrects the usp to pop those two arguments
rts
/*
* update profiling information for the user
* addupc(pc, &u.u_prof, ticks)
*/
_addupc:
movl a2,sp@- | scratch register
movl sp@(12),a2 | get &u.u_prof
movl sp@(8),d0 | get user pc
subl a2@(8),d0 | pc -= pr->pr_off
jlt Lauexit | less than 0, skip it
movl a2@(12),d1 | get pr->pr_scale
lsrl #1,d0 | pc /= 2
lsrl #1,d1 | scale /= 2
| mulul d1,d0 | pc /= scale
moveml d0/d1,sp@-
jbsr ___mulsi3
lea sp@(8),sp
moveq #14,d1
lsrl d1,d0 | pc >>= 14
bclr #0,d0 | pc &= ~1
cmpl a2@(4),d0 | too big for buffer?
jge Lauexit | yes, screw it
addl a2@,d0 | no, add base
| movl d0,sp@- | push address
| jbsr _fusword | grab old value
| movl sp@+,a0 | grab address back
| cmpl #-1,d0 | access ok
| jeq Lauerror | no, skip out
movel d0,a0
movew a0@,d0
addw sp@(18),d0 | add tick to current value
movew d0,a0@
| movl d0,sp@- | push value
| movl a0,sp@- | push address
| jbsr _susword | write back new value
| addql #8,sp | pop params
| tstl d0 | fault?
| jeq Lauexit | no, all done
Lauerror:
| clrl a2@(12) | clear scale (turn off prof)
Lauexit:
movl sp@+,a2 | restore scratch reg
rts
_resetfpu:
moveml a5/a6,sp@-
lea Lreset_fpu,a5
movel 4:w,a6
jsr a6@(-30) | Supervisor()
bra Lafter_reset_fpu
Lreset_fpu:
btst #7,(4)@(0x129) | is AFB_68060 set in SysBase->AttnFlags ??
beq Lno_060fpu | found 060 and put 2 more longs on stack
clrl sp@- | prepare 060 fpu null state frame
clrl sp@- | needs 2 additional longs on stack
Lno_060fpu:
clrl sp@-
frestore sp@+
| Note that after using frestore with a null state frame we have
| to set up the control register to restore rounding to truncation
| rather than round-to-nearest, as required by the ANSI C standard.
moveq #72,d0
addl d0,d0
fmovel d0,fpcr
rte
Lafter_reset_fpu:
moveml sp@+,a5/a6
rts